<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>组合模式</title>
  </head>

  <body>
    <button id="btn1">常规赛</button>
    <button id="btn2">季后赛</button>
    <button id="btn3">总决赛</button>

    <!-- 组合模式父类封装 -->
    <script>
      /* 组合父类：封装了所有组合共有的特性 */
      class Compose {
        /* 创建组合时初始化组件列表 */
        constructor(name) {
          this.name = name;

          // 初始化组件列表
          this.components = [];
        }

        /* 添加组件 */
        addComponent(com) {
          this.components.push(com);
        }

        /* 移除组件 */
        removeComponent(com) {
          this.components = this.components.filter((c) => c !== com);
        }

        /* 给所有组件下达命令 */
        command(cmd) {
          /* 让所有组件响应命令 */
          this.components.forEach((c) => c.onCommand(cmd));
        }
      }

      /* 组件父类：封装了所有组件共有的特性 */
      class Component {
        /* 创建组件时给一个名字 */
        constructor(name) {
          this.name = name;
        }

        /* 响应组合的命令 */
        onCommand(cmd) {
          console.log(`${this.name}响应了组合的命令${cmd}`);
        }
      }
    </script>

    <!-- 组合模式的具体实现子类 -->
    <script>
      /* 封装组合类的具体实现类：NBA联盟 */
      class NBA extends Compose {
        /* 筛选出指定数量的队伍 */
        pickTeams(n) {
          const arr = [];

          //   只要球队数量还不够
          while (arr.length < n) {
            let team =
              this.components[parseInt(Math.random() * this.components.length)];
            /* arr中不包含指定team时 */
            if (arr.indexOf(team) === -1) {
              arr.push(team);
            }
          }

          // 返回挑选出来的球队
          return arr;
        }

        /* 覆盖override父类方法 */
        command(cmd) {
          /* 让所有组件响应命令 */

          /* 如果cmd是【总决赛】 先选出两只球队 再对这两只球队下命令 */
          if (cmd === "总决赛") {
            this.pickTeams(2).forEach((c) => c.onCommand(cmd));
          } else {
            this.components.forEach((c) => c.onCommand(cmd));
          }
        }
      }

      /* 封装组件类的具体实现类：NBA球队 */
      class NBATeam extends Component {
        /* 重写override父类的onCommand方法 */
        onCommand(cmd) {
          // 调用父类的onCommand方法
          super.onCommand(cmd);

          /* 扩展父类方法 */
          switch (cmd) {
            case "常规赛":
              console.log(`${this.name}认真打`);
              break;
            case "季后赛":
              console.log(`${this.name}玩命打`);
              break;
            case "总决赛":
              console.log(`${this.name}豁出命地打`);
              break;

            default:
              break;
          }
        }
      }
    </script>

    <!-- 业务逻辑 -->
    <script>
      // 创建一个组合实例
      const nba = new NBA("NBA");

      /* 添加/注册组件 */
      nba.addComponent(new NBATeam("洛杉矶唬人队"));
      nba.addComponent(new NBATeam("休斯顿火箭队"));
      nba.addComponent(new NBATeam("纽约尼克斯队"));
      nba.addComponent(new NBATeam("波士顿凯子队"));

      btn1.onclick = (e) => nba.command("常规赛");
      btn2.onclick = (e) => nba.command("季后赛");
      btn3.onclick = (e) => nba.command("总决赛");
    </script>

  </body>
</html>
